package database

import (
	"reflect"
	"fmt"
	"errors"
)

// record struct information
var records map[string]map[string]rowStruct

func init() {
	records = map[string]map[string]rowStruct{}
}

// Record struct
type Record struct {
	db *Db
	rv      reflect.Value
	rt      reflect.Type
	rs map[string]rowStruct
	isSlice bool
}

// parse struct information
func (this *Record) parseData(data interface {}) {
	rv := reflect.ValueOf(data)
	// if pointer, get inner value
	if rv.Type().Kind().String() == "ptr" {
		rv = reflect.Indirect(reflect.ValueOf(data))
		// if inner value is a slice, save to this.rv and get type from slice element
		if rv.Type().Kind().String() == "slice" {
			this.rv = rv
			this.isSlice = true
			// get type from element
			this.rt = rv.Type().Elem()
		}else {
			this.rv = rv
			this.isSlice = false
			this.rt = rv.Type()
		}
	}
	key := fmt.Sprint(this.rt)
	if records[key] == nil {
		records[key] = mapStruct(this.rt)
	}
	this.rs = records[key]
}

// Query rows and map to slice struct
func (this *Record) Query(sqlStr string, args...interface {}) error {
	if this.isSlice == false {
		return errors.New("invalid slice struct for record querying columns")
	}
	rows, e := this.db.Query(sqlStr, args...)
	if e != nil {
		return e
	}
	if len(rows) < 1 {
		return nil
	}
	for _, row := range rows {
		rv := rowMapStruct(this.rt, row, this.rs)
		this.rv.Set(reflect.Append(this.rv, rv.Elem()))
	}
	return nil
}

// Query one row and map to single struct
func (this *Record) One(sqlStr string, args...interface {}) error {
	if this.isSlice {
		return errors.New("can not set slide struct for querying one column")
	}
	row, e := this.db.One(sqlStr, args...)
	if e != nil {
		return e
	}
	if len(row) < 1 {
		return nil
	}
	this.rv.Set(rowMapStruct(this.rt, row, this.rs).Elem())
	return nil
}
